module Main where

import Prelude

import Data.Argonaut (decodeJson, fromBoolean, fromString, jsonParser, stringify)
import Data.Array as Arr
import Data.Either (Either(..), fromRight)
import Data.Int (toNumber)
import Data.Js (jslog)
import Data.Maybe (Maybe(..), fromJust)
import Data.Nullable (notNull, null)
import Data.Time.Duration (Milliseconds(..))
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (delay, launchAff, launchAff_)
import Effect.Class (liftEffect)
import Effect.Class.Console (log, logShow)
import Foreign.Object as O
import IPFS.Client (Client, fromMultiaddr)
import IPFS.Client as C
import IPFS.Client.Command.Bitswap as BW
import IPFS.Client.Command.Block as Block
import IPFS.Client.Command.Bootstrap as BT
import IPFS.Client.Command.Config as Cfg
import IPFS.Client.Command.Files.MFS as MFS
import IPFS.Client.Command.Files.Regular (GetFileStreamInfo(..))
import IPFS.Client.Command.Files.Regular as RFS
import IPFS.Client.Command.Key as Key
import IPFS.Client.Command.Log as Log
import IPFS.Client.Command.Misc as Misc
import IPFS.Client.Command.Object as OJ
import IPFS.Client.Command.Pin as Pin
import IPFS.Client.Command.Repo as Repo
import IPFS.Client.Command.Stats as Stats
import IPFS.Client.Command.Swarm as Sw
import IPFS.Client.Utils.Multipart (mkMultipart)
import IPFS.Client.Utils.PrepareFile (defPrepareFileOptions, prepareFile)
import IPFS.Client.Utils.SendFilesStream (mkSendFileStream, defSendFileStreamOptions)
import IPFS.Client.Utils.SendRequest (closeResponse)
import IPFS.Client.Utils.Types (LocalFile(..), SendFile, SendFileContent(..))
import IPFS.Multiaddr as MAddr
import Network.HTTP as HTTP
import Node.Buffer as Buf
import Node.Encoding (Encoding(..))
import Node.Path as Path
import Node.SteamEx.Readable as SR
import Node.Stream (end, onError)
import Node.Stream.Helper as SH
import Node.Stream.Helper.NdJson as ND
import Node.Stream.Helper.Split2 as S
import Node.StreamEx.Types (Readable, Transform, Writable, toReadable, toWritable)
import Node.StreamEx.Writable as SW
import Node.URL as URL
import Partial.Unsafe (unsafePartial)

main::Effect Unit
main = do
   log "start main"
   let maddr = MAddr.fromString "/ip4/47.52.99.90/tcp/5001" >>= fromMultiaddr 
   let client = unsafePartial $ fromRight $  maddr
   logShow client
   --testStream
   --testGCCommand client
   --testBitswapCommand client
   --testWantJson
   --testPing client
   --testConfig client
   --testSendFileStream client
   --testPrepareFile
   --testMFSWrite client
   testBootstrap client
   --testPinFile client
   --testBlock client
   --testRegularFile client
   --testStat client
   --testLog client
   --testObject client
   log "main end"


testObject::C.Client -> Effect Unit
testObject client = do
  launchAff_ do
    resp2 <- OJ.stat client "QmS7pscMz1uivhPBvPV18kfFnHS7ZMcbR7vknLFEV46EKW"
    logShow resp2

testLog::C.Client -> Effect Unit
testLog client = do
  launchAff_ do
    resp2 <- Log.level client "all" Log.Warning
    logShow resp2

testKey::C.Client -> Effect Unit
testKey client = do
  launchAff_ do
   --resp2 <- Key.gen client "fucker" "rsa" Nothing
   --liftEffect $ logShow resp2
   --rrr <- Key.rm client "fucker"
   --liftEffect $ logShow rrr
   resp2 <- Key.rename client "aaa" "fuck" Nothing
   liftEffect $ logShow resp2
   --resp <- Key.list client
   --liftEffect $ logShow resp

testStat::C.Client -> Effect Unit
testStat client = do
 
  _ <-Stats.bwPoll client (\resp -> do
                            launchAff_ $ do
                               _ <- delay $ Milliseconds (toNumber 1)
                               liftEffect $ closeResponse resp
                          ) jslog Nothing Nothing Nothing
  launchAff_ do
   resp <- Stats.repo client
   liftEffect $ logShow resp
   resp2 <- Stats.bw client Nothing Nothing Nothing
   liftEffect $ logShow resp2
   resp3 <- Stats.bitswap client
   liftEffect $ logShow resp3
  
testRegularFile::C.Client -> Effect Unit
testRegularFile client = do
 launchAff_ do
   resp <- RFS.ls client "QmStxQQXB3Bd5KXqQ5Qnf6C95k6FohopisQYKYsk4zt1Kx" Nothing Nothing Nothing Nothing
   liftEffect $ logShow resp
   resp2 <- RFS.get client "QmZ7ZRYF1pzNgThLwqmkS6edgRJSbw2XEgg36LcmerHFRp"
   liftEffect $ logShow resp2
   resp3 <- RFS.getReadableStream client "QmZ7ZRYF1pzNgThLwqmkS6edgRJSbw2XEgg36LcmerHFRp"
   liftEffect $ case resp3 of
                    Left  l -> log l
                    Right (GetFileStreamInfo r) -> SR.onData r.content (\buf -> do
                                                                         str <- Buf.toString UTF8 buf
                                                                         jslog str
                                                                       )
   pure unit
 {-catResp <- RFS.cat client "QmZ7ZRYF1pzNgThLwqmkS6edgRJSbw2XEgg36LcmerHFRp" Nothing Nothing
   liftEffect $ case catResp of 
                  Left r  -> logShow r
                  Right v -> do 
                        str <- Buf.toString UTF8 v
                        log str
    liftEffect $ logShow catResp
   
   eRespStream <- RFS.catReadableStream  client "QmZ7ZRYF1pzNgThLwqmkS6edgRJSbw2XEgg36LcmerHFRp" Nothing Nothing
   liftEffect $ case eRespStream of
     Left  l -> log l
     Right r -> SR.onData r logShow-}
   
   

testBlock::C.Client -> Effect Unit
testBlock client = do
  launchAff_ do
    resp <- Block.stat client "QmUpgeg514FFEa2Hou93LQcN2YzT2py6itoKueSsyTjuQz"
    liftEffect $ logShow resp
    resp2 <- Block.get client "QmUpgeg514FFEa2Hou93LQcN2YzT2py6itoKueSsyTjuQz"
    liftEffect $ logShow resp2

testPinFile::C.Client -> Effect Unit
testPinFile client = do
  launchAff_ do
    resp <- Pin.add client "QmUpgeg514FFEa2Hou93LQcN2YzT2py6itoKueSsyTjuQz" Nothing
    liftEffect $ logShow resp
    files <- Pin.ls client Nothing Nothing Nothing
    liftEffect $ logShow files
    resp2 <- Pin.rm client "QmUpgeg514FFEa2Hou93LQcN2YzT2py6itoKueSsyTjuQz" Nothing
    liftEffect $ logShow resp2
    files2 <- Pin.ls client Nothing Nothing Nothing
    liftEffect $ logShow files2

testMFSWrite::C.Client -> Effect Unit
testMFSWrite client = do
 buf <- Buf.fromString "testMFSWrite" UTF8
 MFS.write client "/a.txt" [LocalFileBuffer buf] MFS.defWriteOptions Nothing logShow
 pure unit

testSendFileStream::C.Client -> Effect Unit
testSendFileStream client = do
 stream::Writable LocalFile <- mkSendFileStream client (defSendFileStreamOptions {qs = O.fromFoldable ["create" /\ fromBoolean true],
                                                              args = Just [fromString "/b.txt"]}) Nothing "files/write" (jslog)
 buf <- Buf.fromString "无駄无駄无駄无駄无駄无駄无駄无駄无駄无駄无駄无駄无駄无駄无駄" UTF8
 _ <- SW.write (toWritable stream) (LocalFileBuffer buf) (Just "utf8") Nothing
 SW.end (toWritable stream::Writable LocalFile) null (Just "utf8") Nothing
 log "testSendFileStream Func End"

testPrepareFile::Effect Unit
testPrepareFile = do 
   objs <- prepareFile [LocalFilePath "/home/yangdao/Project/GO/go-multiaddr"] defPrepareFileOptions
   let (obj::SendFile) = unsafePartial $ fromJust $ Arr.index objs 0
   case obj.content of
     SendReadable read -> do
                          SR.onData read (\buf -> do
                                            str <- Buf.toString UTF8 buf
                                            log str
                                         )
                          log "readable"
     otherwise         -> pure unit

testPath::Effect Unit
testPath = do
 resolvePath <- Path.resolve ["???"] "./fucker.txt"
 log resolvePath
 pure unit

testMultipart::Effect Unit
testMultipart = do
 part::Transform Buf.Buffer <- mkMultipart
 bufArr <- Buf.fromArray [0]
 _ <- SW.write (toWritable part::Writable Buf.Buffer) bufArr Nothing Nothing
 SR.onData (toReadable part::Readable Buf.Buffer) (\buf -> log $ "???" <> (show buf) <> "???")
 SW.end (toWritable part::Writable Buf.Buffer) (notNull bufArr) Nothing Nothing
 log "testMultipart Func End"

testConfig::Client -> Effect Unit
testConfig client =  do
  launchAff_ $ do 
      resp <- Cfg.show client 
      liftEffect $ jslog resp
      resp2 <- Cfg.get client "API.HTTPHeaders"
      liftEffect $ jslog resp2

testBootstrap::Client -> Effect Unit
testBootstrap client = do
    _<-launchAff $ do 
      resp <- BT.list client 
      liftEffect $ logShow resp
      --resp2 <- BT.add client "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"
      --liftEffect $ logShow resp2
      --resp3 <- BT.rmAll client
      --liftEffect $ logShow resp3
      resp4 <- BT.addDefault client
      liftEffect $ logShow resp4
    pure unit

testShutdown::Client -> Effect Unit
testShutdown client = do
　 _<-launchAff $ do 
      resp <- Misc.shutdown client 
      liftEffect $ logShow resp
  pure unit

testPing::Client -> Effect Unit
testPing client = do
  Misc.ping client "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ" Nothing jslog logShow
  pure unit

testMiscId::Client -> Effect Unit
testMiscId client = do
　 _<-launchAff $ do 
      resp <- Misc.dns client "ipfs.io" (Just true)
      liftEffect $ logShow resp
  pure unit


testConnect::Client -> Effect Unit
testConnect client = do
　 _<-launchAff $ do 
      resp <- Sw.disconnect client "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"
      liftEffect $ logShow resp
  pure unit

testSwarmAddr::Client -> Effect Unit
testSwarmAddr client = do
  _<-launchAff $ do
   resp <- Sw.listenAddr client
   liftEffect $ logShow resp
  pure unit

testSwarmPeers::Client -> Effect Unit
testSwarmPeers client = do
  _<-launchAff $ do
   resp <- Sw.peers client (Just true) Nothing Nothing Nothing
   liftEffect $ logShow resp
  pure unit

testWantJson::Effect Unit
testWantJson = do
  let str = "{\"Keys\":[{\"/\":\"dfpodsajfdsj\"},{\"/\":\"dfpodsajfdsj\"},{\"/\":\"dfpodsajfdsj\"}]}"
  case jsonParser str of
    Left  l -> logShow l
    Right j ->   let  (wantList::Either String BW.Wantlist) = decodeJson j
                 in  logShow wantList
  logShow "end"

testBitswapCommand::Client -> Effect Unit
testBitswapCommand client = do
 _ <- launchAff $ do  
                   resp <- BW.wantlist client Nothing
                   logShow resp
 pure unit

testGCCommand::Client -> Effect Unit
testGCCommand client = do  
   Repo.gc client (Just true) Nothing jslog (\eData -> logShow (stringify <$> eData))
   pure unit


testStream::Effect Unit
testStream = do
  req <- HTTP.request reqOptions (\resp -> do
        let readW = HTTP.responseAsStream resp
        out <- S.split2
        _ <- SH.pump readW out (\err -> pure unit)
        jslog out
        ND.onJsonEither  out  (\b -> do
                                 logShow  (stringify <$> b)
                              )
        onError out (\err -> jslog err)
        logShow "testStream end"
     )
  let reqWriter = HTTP.requestAsStream req
  end reqWriter (pure unit)
  pure unit
 where
    reqOptions = { reqURL:URL.parse "http://192.168.1.7:8080/test.json",reqMethod:HTTP.GET,reqHeader:O.empty}